/**
 ******************************************************************************
 * @file           : bsp_iic.c
 * @brief          : Hardware I2C Driver Implementation (STM32H7xx)
 ******************************************************************************
 * @attention
 *
 * 硬件I2C驱动程序实现文件（基于STM32 HAL库）
 * 提供标准I2C主机功能
 * 支持内存读写和主机收发
 * 完善的错误处理机制
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./BSP/IIC/bsp_iic.h"
#include "./BSP/IIC/bsp_iic_config.h"

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static I2C_HandleTypeDef sg_i2c_handle;     /*!< I2C句柄 */

/* Private function prototypes -----------------------------------------------*/
static void IIC_MspInit(I2C_HandleTypeDef *hi2c);
static void IIC_MspDeInit(I2C_HandleTypeDef *hi2c);
static IIC_Error_e IIC_HAL_Error_Convert(HAL_StatusTypeDef hal_status);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       I2C MSP初始化
 *
 * @param       hi2c: I2C句柄指针
 *
 * @retval      无
 *
 * @note        配置GPIO和时钟
 */
static void IIC_MspInit(I2C_HandleTypeDef *hi2c)
{
    GPIO_InitTypeDef gpio_init = {0};
    
    if (hi2c->Instance == IIC_I2Cx)
    {
        /* 使能GPIO时钟 */
        IIC_SCL_GPIO_CLK_ENABLE();
        IIC_SDA_GPIO_CLK_ENABLE();

        /* 使能I2C时钟 */
        IIC_I2Cx_CLK_ENABLE();
        
        /* 配置SCL引脚 */
        gpio_init.Pin       = IIC_SCL_GPIO_PIN;
        gpio_init.Mode      = GPIO_MODE_AF_OD;          /* 开漏输出 */
        gpio_init.Pull      = GPIO_PULLUP;              /* 上拉 */
        gpio_init.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
        gpio_init.Alternate = IIC_GPIO_AF;
        HAL_GPIO_Init(IIC_SCL_GPIO_PORT, &gpio_init);
        
        /* 配置SDA引脚 */
        gpio_init.Pin       = IIC_SDA_GPIO_PIN;
        HAL_GPIO_Init(IIC_SDA_GPIO_PORT, &gpio_init);
        
        log_d("I2C MSP initialized");
    }
}

/**
 * @brief       I2C MSP反初始化
 *
 * @param       hi2c: I2C句柄指针
 *
 * @retval      无
 *
 * @note        释放GPIO和时钟
 */
static void IIC_MspDeInit(I2C_HandleTypeDef *hi2c)
{
    if (hi2c->Instance == IIC_I2Cx)
    {
        /* 禁用时钟 */
        IIC_I2Cx_CLK_DISABLE();
        
        /* 释放GPIO引脚 */
        HAL_GPIO_DeInit(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN);
        HAL_GPIO_DeInit(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN);
        
        log_d("I2C MSP deinitialized");
    }
}

/**
 * @brief       HAL状态码转换为IIC错误码
 *
 * @param       hal_status: HAL库返回的状态码
 *
 * @retval      IIC_Error_e: IIC错误码
 *
 * @note        统一错误码处理
 */
static IIC_Error_e IIC_HAL_Error_Convert(HAL_StatusTypeDef hal_status)
{
    switch (hal_status)
    {
        case HAL_OK:
            return IIC_OK;
        case HAL_ERROR:
            return IIC_ERROR;
        case HAL_BUSY:
            return IIC_ERROR_BUSY;
        case HAL_TIMEOUT:
            return IIC_ERROR_TIMEOUT;
        default:
            return IIC_ERROR;
    }
}

/* Exported functions --------------------------------------------------------*/

/**
 * @brief       I2C初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        配置I2C外设，初始化GPIO
 */
void IIC_Init(void)
{
    /* I2C配置 */
    sg_i2c_handle.Instance              = IIC_I2Cx;
    sg_i2c_handle.Init.Timing           = 0x00707CBB;  /* 100kHz @ 64MHz */
    sg_i2c_handle.Init.OwnAddress1      = 0x00;        /* 主机地址（可任意设置） */
    sg_i2c_handle.Init.AddressingMode   = I2C_ADDRESSINGMODE_7BIT;
    sg_i2c_handle.Init.DualAddressMode  = I2C_DUALADDRESS_DISABLE;
    sg_i2c_handle.Init.OwnAddress2      = 0x00;
    sg_i2c_handle.Init.GeneralCallMode  = I2C_GENERALCALL_DISABLE;
    sg_i2c_handle.Init.NoStretchMode    = I2C_NOSTRETCH_DISABLE;
    
    /* MSP初始化 */
    IIC_MspInit(&sg_i2c_handle);
    
    /* 初始化I2C外设 */
    if (HAL_I2C_Init(&sg_i2c_handle) != HAL_OK)
    {
        log_e("I2C initialization failed");
        return;
    }
    
    log_i("I2C initialized successfully (Speed: %d Hz)", IIC_SPEED);
}

/**
 * @brief       I2C反初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        释放I2C资源
 */
void IIC_DeInit(void)
{
    HAL_I2C_DeInit(&sg_i2c_handle);
    IIC_MspDeInit(&sg_i2c_handle);
    
    log_i("I2C deinitialized");
}

/**
 * @brief       扫描I2C总线
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        扫描0x00-0xFF所有地址，打印发现的设备
 */
void IIC_Scan_Bus(void)
{
    uint8_t addr;
    uint8_t count = 0;
    
    log_i("Scanning I2C bus...");
    
    for (addr = 0x00; addr < 0xFF; addr += 2)  /* I2C地址为8位（包含R/W位） */
    {
        if (IIC_Is_Device_Ready(addr, 1) == IIC_OK)
        {
            log_i("Found device at address: 0x%02X", addr);
            count++;
        }
    }
    
    log_i("Total %d devices found on I2C bus", count);
}

/**
 * @brief       写设备内存
 *
 * @param[in]   dev_addr: 设备地址
 * @param[in]   mem_addr: 内存地址
 * @param[in]   mem_addr_size: 内存地址大小（1或2字节）
 * @param[in]   data: 数据指针
 * @param[in]   len: 数据长度
 *
 * @retval      IIC_OK: 成功
 * @retval      IIC_ERROR_PARAM: 参数错误
 * @retval      IIC_ERROR_TIMEOUT: 超时
 * @retval      IIC_ERROR_BUSY: 总线忙
 * @retval      IIC_ERROR: 其他错误
 *
 * @note        适用于EEPROM、传感器寄存器等设备
 */
IIC_Error_e IIC_Write_Mem(uint16_t dev_addr, uint16_t mem_addr, 
                           uint8_t mem_addr_size, const uint8_t *data, uint16_t len)
{
    HAL_StatusTypeDef status;
    
    /* 参数检查 */
    if (data == NULL || len == 0)
    {
        log_e("Invalid parameters");
        return IIC_ERROR_PARAM;
    }
    
    if (mem_addr_size != I2C_MEMADD_SIZE_8BIT && mem_addr_size != I2C_MEMADD_SIZE_16BIT)
    {
        log_e("Invalid memory address size");
        return IIC_ERROR_PARAM;
    }
    
    /* 写内存 */
    status = HAL_I2C_Mem_Write(&sg_i2c_handle, dev_addr, mem_addr, 
                               mem_addr_size, (uint8_t*)data, len, IIC_TIMEOUT_MS);
    
    if (status != HAL_OK)
    {
        log_e("I2C write memory failed (addr: 0x%02X, status: %d)", dev_addr, status);
    }
    
    return IIC_HAL_Error_Convert(status);
}

/**
 * @brief       读设备内存
 *
 * @param[in]   dev_addr: 设备地址
 * @param[in]   mem_addr: 内存地址
 * @param[in]   mem_addr_size: 内存地址大小（1或2字节）
 * @param[out]  data: 数据缓冲区指针
 * @param[in]   len: 数据长度
 *
 * @retval      IIC_OK: 成功
 * @retval      IIC_ERROR_PARAM: 参数错误
 * @retval      IIC_ERROR_TIMEOUT: 超时
 * @retval      IIC_ERROR_BUSY: 总线忙
 * @retval      IIC_ERROR: 其他错误
 *
 * @note        适用于EEPROM、传感器寄存器等设备
 */
IIC_Error_e IIC_Read_Mem(uint16_t dev_addr, uint16_t mem_addr, 
                          uint8_t mem_addr_size, uint8_t *data, uint16_t len)
{
    HAL_StatusTypeDef status;
    
    /* 参数检查 */
    if (data == NULL || len == 0)
    {
        log_e("Invalid parameters");
        return IIC_ERROR_PARAM;
    }
    
    if (mem_addr_size != I2C_MEMADD_SIZE_8BIT && mem_addr_size != I2C_MEMADD_SIZE_16BIT)
    {
        log_e("Invalid memory address size");
        return IIC_ERROR_PARAM;
    }
    
    /* 读内存 */
    status = HAL_I2C_Mem_Read(&sg_i2c_handle, dev_addr, mem_addr, 
                              mem_addr_size, data, len, IIC_TIMEOUT_MS);
    
    if (status != HAL_OK)
    {
        log_e("I2C read memory failed (addr: 0x%02X, status: %d)", dev_addr, status);
    }
    
    return IIC_HAL_Error_Convert(status);
}

/**
 * @brief       获取错误描述字符串
 *
 * @param[in]   error: IIC错误码
 *
 * @retval      错误描述字符串
 *
 * @note        用于调试和日志输出
 */
const char* IIC_Get_Error_String(IIC_Error_e error)
{
    switch (error)
    {
        case IIC_OK:            return "Success";
        case IIC_ERROR_PARAM:   return "Invalid parameter";
        case IIC_ERROR_TIMEOUT: return "Timeout";
        case IIC_ERROR_BUSY:    return "Bus busy";
        case IIC_ERROR_NACK:    return "No ACK received";
        case IIC_ERROR_AF:      return "Acknowledge failure";
        case IIC_ERROR_BERR:    return "Bus error";
        case IIC_ERROR_ARLO:    return "Arbitration lost";
        case IIC_ERROR_OVR:     return "Overrun/Underrun";
        default:                return "Unknown error";
    }
}

/**
 * @brief       主机接收数据
 *
 * @param[in]   dev_addr: 设备地址
 * @param[out]  data: 数据缓冲区指针
 * @param[in]   len: 数据长度
 *
 * @retval      IIC_OK: 成功
 * @retval      IIC_ERROR_PARAM: 参数错误
 * @retval      IIC_ERROR_TIMEOUT: 超时
 * @retval      IIC_ERROR_BUSY: 总线忙
 * @retval      IIC_ERROR: 其他错误
 *
 * @note        直接接收数据，不带内存地址
 */
IIC_Error_e IIC_Master_Receive(uint16_t dev_addr, uint8_t *data, uint16_t len)
{
    HAL_StatusTypeDef status;
    
    /* 参数检查 */
    if (data == NULL || len == 0)
    {
        log_e("Invalid parameters");
        return IIC_ERROR_PARAM;
    }
    
    /* 接收数据 */
    status = HAL_I2C_Master_Receive(&sg_i2c_handle, dev_addr, data, len, IIC_TIMEOUT_MS);
    
    if (status != HAL_OK)
    {
        log_e("I2C master receive failed (addr: 0x%02X, status: %d)", dev_addr, status);
    }
    
    return IIC_HAL_Error_Convert(status);
}

/**
 * @brief       检查设备就绪
 *
 * @param[in]   dev_addr: 设备地址
 * @param[in]   retry: 重试次数
 *
 * @retval      IIC_OK: 设备就绪
 * @retval      IIC_ERROR_TIMEOUT: 设备不响应
 * @retval      IIC_ERROR_BUSY: 总线忙
 *
 * @note        通过发送设备地址检测设备是否存在
 */
IIC_Error_e IIC_Is_Device_Ready(uint16_t dev_addr, uint8_t retry)
{
    HAL_StatusTypeDef status;
    
    status = HAL_I2C_IsDeviceReady(&sg_i2c_handle, dev_addr, retry, IIC_TIMEOUT_MS);
    
    return IIC_HAL_Error_Convert(status);
}
